from flask import Flask
import os

from sqlalchemy import create_engine

from auth import router as AuthRouter
from do.vo import JWTIdendity, RulePath
from common.constant import message as msg

from service.casbin import init_casbin, upsert_rule

from utils import get_env
from utils._db import gen_session
from utils import from_result, safe_load_dotenv
from utils.config import load_jwt_keys, workdir

from datetime import timedelta

from flask_jwt_extended import JWTManager

from models.users import Users

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


if workdir is None:
    raise RuntimeError("Environment variable WORKDIR is not set")
else:
    safe_load_dotenv(os.path.join(workdir, "config", ".env"))


app = Flask(__name__, static_folder=None)

# 关于casbin
enforcer = init_casbin()

app.enforcer = enforcer

# 关于JWT
JWT_PRIVATE_KEY, JWT_PUBLIC_KEY = load_jwt_keys(workdir)

JWT_EXPIRE = float(get_env("jwt.ttl"))

JWT_ALGORITHM = get_env("jwt.algorithm")

JWT_SECRET_KEY = get_env("jwt.secret_key")

app.config["JWT_SECRET_KEY"] = JWT_SECRET_KEY
# 设置普通JWT过期时间
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=JWT_EXPIRE)
# 设置刷新JWT过期时间
app.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=30)

# 公私钥
app.config["JWT_PRIVATE_KEY"] = JWT_PRIVATE_KEY
app.config["JWT_PUBLIC_KEY"] = JWT_PUBLIC_KEY

jwt = JWTManager(app)


@jwt.user_identity_loader
def user_identity_lookup(user):
    return str(user)


@jwt.user_lookup_loader
def user_lookup_callback(_jwt_header, jwt_data):
    identity = jwt_data["sub"]
    ss = gen_session()

    # user = (Users.select().where((Users.phone_num == identity))).first()
    user = (
        ss.query(Users.phone_num, Users.emp_number, Users.username, Users.department, Users.position, Users.is_admin)
        .filter(Users.phone_num == identity)
        .first()
    )
    # type <class 'sqlalchemy.engine.row.Row'>

    # print(user, type(user))

    ss.close()

    return JWTIdendity(**user._mapping)
    # return JWTIdendity(**user._asdict()) # 一样


@jwt.unauthorized_loader
def custom_unauthorized(err_msg):
    return from_result(code=401, message=msg.JWT_UNAUTHORIZED)


@jwt.invalid_token_loader
def custom_invalid_token(err_msg):
    return from_result(code=422, message=msg.JWT_INVALID)


@jwt.expired_token_loader
def custom_expired_token(jwt_header, jwt_payload):
    return from_result(code=401, message=msg.JWT_EXPIRED)


@jwt.user_lookup_error_loader
def custom_user_lookup_error(_jwt_header, jwt_data):
    return from_result(code=401, message=msg.JWT_USER_NOT_FOUND)


# 蓝图注册
app.register_blueprint(AuthRouter)

# 开发模式测试
if os.getenv("development") == "true":
    from test import router as TestRouter

    app.register_blueprint(TestRouter)

    def print_routes():
        for rule in app.url_map.iter_rules():
            methods = list(rule.methods)
            view_func = app.view_functions[rule.endpoint]
            print(
                f"Endpoint: {rule.endpoint}, Path: {rule}, Methods: {methods}, description: {view_func.__doc__ or "No description"}"
            )


def upsert_rule_path():
    ss = gen_session()
    for rule in app.url_map.iter_rules():
        view_func = app.view_functions[rule.endpoint]
        upsert_rule(
            ss,
            RulePath(
                **{
                    "endpoint": rule.endpoint,
                    "rule": str(rule),
                    "methods": sorted(rule.methods),
                    "description": view_func.__doc__ or "No description",
                }
            ),
        )

    ss.close()


def print_startup_banner(host: str, port: str):
    addr = f"{host}:{port}"
    logger.info("=" * 45)
    logger.info(
        r"""(♥◠‿◠)ﾉﾞ     ლ(´ڡ`ლ)ﾞ
  _____   _  Flask启动成功   _
 |  ___| | |   __ _   ___  | | __
 | |_    | |  / _` | / __| | |/ /
 |  _|   | | | (_| | \__ \ |   < 
 |_|     |_|  \__,_| |___/ |_|\_\
🚀 服务地址: http://%s""",
        addr,
    )
    logger.info("=" * 45)
